package com.ikingtech.framework.sdk.data.mybatisplus.helper.base;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ikingtech.framework.sdk.base.model.BaseModel;
import com.ikingtech.framework.sdk.base.model.BaseQueryParam;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.data.mybatisplus.entity.BaseEntity;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.PostRequest;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Collections;
import java.util.List;

/**
 * @author tie yan
 */
@RequiredArgsConstructor
public abstract class AbstractController<T extends BaseModel, E extends BaseEntity, Q extends BaseQueryParam> {

    protected final BaseRepository<E, Q> repo;

    protected final Class<T> modelClass;

    protected final Class<E> entityClass;

    @Transactional(rollbackFor = Exception.class)
    @PostRequest(order = 1, value = "/add", summary = "新增", description = "新增")
    public R<String> add(@Parameter(name = "model", description = "新增信息")
                         @RequestBody T model) {
        this.beforeSave(model);
        E entity = this.entityConvert(model);
        this.repo.save(entity);
        this.afterSave(model, entity);
        return R.ok(entity.getId());
    }

    @Transactional(rollbackFor = Exception.class)
    @PostRequest(order = 2, value = "/delete", summary = "删除", description = "删除")
    public R<Object> delete(@Parameter(name = "id", description = "编号")
                            @RequestBody String id) {
        this.beforeDelete(id);
        this.repo.removeById(id);
        this.afterDelete(id);
        return R.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    @PostRequest(order = 3, value = "/update", summary = "更新", description = "更新")
    public R<Object> update(@Parameter(name = "model", description = "更新信息")
                            @RequestBody T model) {
        this.beforeUpdate(model);
        E entity = this.entityConvert(model);
        this.repo.updateById(entity);
        this.afterUpdate(model, entity);
        return R.ok(entity.getId());
    }

    @PostRequest(order = 4, value = "/list/page", summary = "分页查询", description = "分页查询")
    public R<List<T>> page(@Parameter(name = "queryParam", description = "查询条件")
                           @RequestBody Q queryParam) {
        queryParam.setIds(this.beforeQuery(queryParam));
        return R.ok(PageResult.build(this.repo.page(new Page<>(queryParam.getPage(), queryParam.getRows()),
                this.repo.conditionalWrapper(queryParam))).convertBatch(this::modelConvert));
    }

    @PostRequest(order = 5, value = "/list/all", summary = "全量查询", description = "全量查询")
    public R<List<T>> all() {
        return R.ok(this.modelConvert(this.repo.list(this.repo.tenantWrapper())));
    }

    @PostRequest(order = 6, value = "/detail", summary = "详情", description = "详情")
    public R<T> detail(@Parameter(name = "id", description = "编号")
                       @RequestBody String id) {
        E entity = this.repo.getById(id);
        if (null == entity) {
            throw new FrameworkException("notFound");
        }
        return R.ok(this.modelConvert(entity));
    }

    @PostRequest(order = 4, value = "/list", summary = "根据条件查询", description = "根据条件查询")
    public R<List<T>> list(@Parameter(name = "queryParam", description = "查询条件")
                           @RequestBody Q queryParam) {
        queryParam.setIds(this.beforeQuery(queryParam));
        return R.ok(this.modelConvert(this.repo.list(this.repo.conditionalWrapper(queryParam))));
    }

    protected void beforeSave(T ignoredModel) {

    }

    protected void afterSave(T ignoredModel, E ignoredEntity) {

    }

    protected void beforeDelete(String ignoredId) {

    }

    protected void afterDelete(String ignoredId) {

    }

    protected void beforeUpdate(T ignoredModel) {

    }

    protected void afterUpdate(T ignoredModel, E ignoredEntity) {

    }

    protected List<String> beforeQuery(Q ignoredQueryParam) {
        return Collections.emptyList();
    }

    protected List<T> modelConvert(List<E> entities) {
        if (Tools.Coll.isBlank(entities)) {
            return Collections.emptyList();
        }
        return Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, this.modelClass));
    }

    protected T modelConvert(E entity) {
        return Tools.Bean.copy(entity, this.modelClass);
    }

    protected E entityConvert(T model) {
        E entity = Tools.Bean.copy(model, this.entityClass);
        if (Tools.Str.isBlank(model.getId())) {
            entity.setId(Tools.Id.uuid());
        }
        return entity;
    }

}
